﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using ITAP.Core.Calculations;
using ITAP.ContourBuilder.Components;
using System.Windows.Forms;
using ITAP.Core.Modelling.Primitives;
using System.Threading;
using ITAP.ContourBuilder.GUI;
using ITAP.Core.Modelling;

namespace ITAP.ContourBuilder.Manipulation
{
    public delegate void ContextMenuItemDelegate();

    public class CommandEnterPolyline : SerializedCommand
    {
        private bool enterStarted = false;
        public CommandEnterPolyline(ContourControl control) : base(control)
        {
        }

        public override void CreateContextMenu()
        {
            base.CreateContextMenu();
            //contextMenu.Items.Add(this.CreateContextMenuItem("Закончить", this.Exit));
            contextMenu.Items.Add(this.CreateContextMenuItem("Замкнуть", this.ClosePolyline));
            contextMenu.Items.Add(this.CreateContextMenuItem("Удалить последний элемент", this.CancelLastElement));
            contextMenu.Items.Add(new ToolStripSeparator());
            contextMenu.Items.Add(this.CreateContextMenuItem("Ввод арки", this.EnterArc));            
        }

        public override void Execute()
        {            
            base.Execute();
        }

        public override void ObtainPeripheryState(GlobalPeripheryState state)
        {
            base.ObtainPeripheryState(state);

            if (state.MouseState.State.Button == System.Windows.Forms.MouseButtons.Left && state.MouseState.MouseMode == MouseMode.Down)
            {
                if (enterStarted == false)
                {
                    enterStarted = true;
                    this.DropFirstElement(state.MouseState.State.Location);
                }
                else
                {
                    if (!this.DisableObtainPeripheryState)
                        this.DropNextElement(state.MouseState.State.Location);
                }
                this.control.UpdateModel();
            }
            else if (state.MouseState.MouseMode == MouseMode.Move && enterStarted)
            {
                this.MoveCurrentElementEnd(state.MouseState.State.Location);
                this.control.UpdateModel();
                //this.control.Invalidate();
            }
            else if (state.MouseState.MouseMode == MouseMode.Up && state.MouseState.State.Button == MouseButtons.Right)
            {
                this.ShowContextMenu();
            }
        }

        public override void DrawOnGraphics(System.Drawing.Graphics g, int screenWidth, int screenHeight, RectangleF modelRectangle, ModelPoint cameraCenter, ModelCoordinateConverter coordinateConverter)
        {
        }

        private ContourElement firstElement = null;
        private ContourElement currentElement = null;
        private ContourModel currentModel = null;
        private void DropFirstElement(Point mouseDownPoint)
        {
            ContourModel model = ContourElementFactory.CreateModel();
            ModelPoint startPoint = this.control.CoordinateConverter.ScreenPointToModelPoint(mouseDownPoint, control.Width, control.Height, control.FullRectangle, control.CameraCenter);
            ModelPoint endPoint = startPoint.Clone() as ModelPoint;
            ContourElement element = ContourElementFactory.CreateLineContourElement(startPoint, endPoint, "");
            currentElement = element;
            firstElement = element;
            model.AddInnerComponent(element);
            currentModel = model;
            control.ContourContainer.AddInnerComponent(model);
        }

        private void MoveCurrentElementEnd(Point mouseMovePoint)
        {
            ModelPoint dest = control.CoordinateConverter.ScreenPointToModelPoint(mouseMovePoint, control.Width, control.Height, control.FullRectangle, control.CameraCenter);
            ModelPoint oldEnd = currentElement.EndPoint;
            currentElement.MoveEndPoint(dest);
            if (control.ContourContainer.HasBounds && !control.ContourContainer.InnerBoundingBox.Contains(currentElement.BoundingBox))
                currentElement.MoveEndPoint(oldEnd);
        }

        private void DropNextElement(Point mouseDownPoint)
        {
            ModelPoint startPoint = this.control.CoordinateConverter.ScreenPointToModelPoint(mouseDownPoint, control.Width, control.Height, control.FullRectangle, control.CameraCenter);
            currentElement.MoveEndPoint(startPoint);
            ModelPoint endPoint = startPoint.Clone() as ModelPoint;
            ContourElement element = ContourElementFactory.CreateLineContourElement(startPoint, endPoint, "");
            ContourConnector connector = ContourElementFactory.CreateConnector(currentElement.EndPoint);
            ContourConnectionProvider.Connect(currentElement, connector, EndType.End);
            ContourConnectionProvider.Connect(element, connector, EndType.Start);
            currentElement = element;
            currentModel.AddInnerComponent(element);
            currentModel.AddInnerComponent(connector);
        }

        private void ClosePolyline()
        {
            ModelPoint oldEnd = currentElement.EndPoint;
            currentElement.MoveEndPoint(firstElement.StartPoint);
            if (control.ContourContainer.HasBounds && !control.ContourContainer.InnerBoundingBox.Contains(currentElement.BoundingBox))
            {
                MessageBox.Show("Невозможно замкнуть контур, потому что контур выходит за границы листа.");
                this.DisableObtainPeripheryState = false;
                currentElement.MoveEndPoint(oldEnd);
                return;
            }

            ContourConnector connector = ContourElementFactory.CreateConnector(currentElement.EndPoint);
            ContourConnectionProvider.Connect(currentElement, connector, EndType.End);
            ContourConnectionProvider.Connect(firstElement, connector, EndType.Start);
            currentModel.AddInnerComponent(connector);

            ContourModel anticlockwiseModel = ContourElementFactory.CreateAntoclockwiseModel(currentModel);
            this.control.ContourContainer.RemoveInnerComponent(currentModel);
            this.control.ContourContainer.AddInnerComponent(anticlockwiseModel);

            currentModel = null;
            currentElement = null;
            this.Exit();
        }

        private void CancelLastElement()
        {
            if (currentElement.StartConnectedComponent != null)
            {                
                IContourComponent connector = currentElement.StartConnectedComponent;
                ContourConnectionProvider.Disconnect(currentElement, currentElement.StartConnectedComponent);


                foreach (IContourComponent connectedElement in connector.ConnectedComponents)
                    if (connectedElement is ContourElement && connectedElement != currentElement)
                    {
                        currentElement.Parent.RemoveInnerComponent(currentElement);
                        currentElement = connectedElement as ContourElement;
                    }

                ContourConnectionProvider.Disconnect(currentElement, connector);
                connector.Parent.RemoveInnerComponent(connector);

                connector = null;                
            }
        }

        private void EnterArc()
        {
            this.DisableObtainPeripheryState = true;

            FormInputArc form = new FormInputArc(currentElement);
            form.IsArcInInnerBounds = false;
            form.ArcHeightChanged += new EventHandler(form_ArcHeightChanged);
            form.FormArcHeightClosed += new FormClosedDelegate(form_FormArcHeightClosed);

            form.ShowDialog();
            form = null;
        }

        void form_FormArcHeightClosed(DialogResult result)
        {
            if (result == DialogResult.OK)
            {
                Point endPoint = peripheryState.MouseState.State.Location;
                this.DisableObtainPeripheryState = false;
            }
            else
            {
                this.DisableObtainPeripheryState = false;
            }
        }

        void form_ArcHeightChanged(object sender, EventArgs e)
        {
            control.Invalidate();
        }
        public override string ToString()
        {
            return "Ввод контура";
        }
    }

}
